package so.sao.code.service.service.impl;

import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import so.sao.code.dto.response.TagStatusInfoDto;
import so.sao.code.service.domain.entity.RangeActivation;
import so.sao.code.service.domain.entity.TagBatch;
import so.sao.code.service.domain.entity.TagBatchConfig;
import so.sao.code.service.domain.service.TagBatchConfigDomainService;
import so.sao.code.service.infrastructure.enums.CodeMessage;
import so.sao.code.service.infrastructure.enums.PrintFileSortDirection;
import so.sao.code.service.infrastructure.enums.TAG_BATCH_TYPE;
import so.sao.code.service.infrastructure.enums.TagRangeStatus;
import so.sao.code.service.repository.RangeActivationDao;
import so.sao.code.service.repository.TagBatchConfigDao;
import so.sao.code.service.repository.TagBatchDao;
import so.sao.code.service.service.TagScrapService;
import so.sao.code.service.service.TagStatusInfoService;
import so.sao.file.datastore.service.FileService;
import so.sao.tag.core.TagCode;
import so.sao.tag.decryptor.TagCodeDriver;
import so.sao.tag.decryptor.TagDecryptor;
import so.sao.top.core.util.CipherZipUtil;
import so.sao.top.core.util.mapper.JsonMapper;
import so.sao.top.core.util.messagecode.CommonCode;

@Service
public class TagStatusInfoServiceImpl implements TagStatusInfoService {

	@Autowired
	protected JsonMapper jsonMapper;

	@Autowired
	private TagDecryptor tagDecryptor;

	@Autowired
	private TagBatchDao tagBatchDao;

	@Autowired
	private TagBatchConfigDao tagBatchConfigDao;

	@Autowired
	private RangeActivationDao rangeActivationDao;

	@Autowired
	private FileService fileService;

	@Value("${sao.code.tempBackFilePath}")
	private String tempBackFilePath;

	@Value("${sao.code.tagCodeBackupPath}")
	private String tagCodeBackupPath;

	@Value("${cloud.container.code-init-files}")
	private String codeInitFiles;

	@Autowired
	private TagBatchConfigDomainService tagBatchConfigDomainService;

	@Autowired
	private TagScrapService tagScrapService;

	@Override
	public TagStatusInfoDto getTagStatusInfoBy(String query, boolean downFlag) throws Exception {
		long seqNum = getTagSeqNum(query);
		if (seqNum > 0) {

			TagBatch tagBatch = tagBatchDao.getTagBatchBySeqNum(seqNum);
			if (tagBatch != null) {// 这个序列号在这个批次里

				TagBatchConfig batchConfig = tagBatchConfigDao.findOne(tagBatch.getTagBatchConfigId());
				if (batchConfig != null) {// 设置过打印格式
					TagStatusInfoDto tagInfo = new TagStatusInfoDto();
					// 基本信息
					tagInfo.setSeqNum(seqNum);
					tagInfo.setDomain(tagBatch.getDomain());
					tagInfo.setSubDomain(tagBatch.getSubDomain());
					tagInfo.setEseId(tagBatch.getEseId());
					tagInfo.setBatchId(tagBatch.getId());
					tagInfo.setBatchName(tagBatch.getName());
					tagInfo.setBatchType(tagBatch.getType().getValue());
					tagInfo.setBatchTypeName(tagBatch.getType().getName());
					tagInfo.setCreateUserId(tagBatch.getCreateUserId());
					tagInfo.setUpdateUserId(tagBatch.getUpdateUserId());
					tagInfo.setStatus(TagRangeStatus.UNACTIVATE.getValue());
					tagInfo.setStatusName(TagRangeStatus.UNACTIVATE.getName());

					// 码报废标志
					tagInfo.setInvalidFlag(tagScrapService.getTagScrapResult(seqNum));

					// 每行标签个数
					Integer tagCountPerLine = tagBatchConfigDomainService.computeCountPerLine(tagBatch,
							batchConfig.getTagCountPerLine());

					if (downFlag) {
						// 加密串,友好码
						tagInfo = setMixAndCodes(tagInfo, tagBatch, tagCountPerLine, batchConfig.getDirection());
					}

					// 激活信息
					tagInfo = setActivityInfo(tagInfo, tagBatch, tagCountPerLine);

					return tagInfo;
				} else {
					return new TagStatusInfoDto(CodeMessage.TagBatchConfigNotSet.getId(),
							query + " /batchId:" + tagBatch.getId() + " not set the config!!");
				}
			}
		}
		return new TagStatusInfoDto(CodeMessage.CanNotFindTagBatch.getId(), query + " /not found the tag!!");
	}

	/**
	 * 设置码的激活登记信息
	 * 
	 * @param tagInfo
	 * @param tagBatch
	 */
	private TagStatusInfoDto setActivityInfo(TagStatusInfoDto tagInfo, TagBatch tagBatch, Integer tagCountPerLine) {
		List<RangeActivation> activityTagRange = rangeActivationDao.findByTagBatchIdAndStatus(tagInfo.getBatchId(),
				TagRangeStatus.ACTIVATED.getValue());
		if (activityTagRange != null) {
			long rangeSeqNum = 0l;
			if (tagInfo.getBatchType() == TAG_BATCH_TYPE.PACKAGE.getValue()) {// 套标(激活时码段只传父标码段)
				Integer lineNum = tagBatch.getTagCount().intValue() / tagCountPerLine;// 总行数

				if (tagInfo.getSeqNum() <= tagBatch.getSeqnumStart() + lineNum - 1) {// 不大于最后一个父标
					rangeSeqNum = tagInfo.getSeqNum();// 父标
				} else {
					// 获取子标对应的父标
					rangeSeqNum = tagBatch.getSeqnumStart()
							+ ((tagInfo.getSeqNum() - (tagBatch.getSeqnumStart() + lineNum)) / (tagCountPerLine - 1));
				}

			} else {
				rangeSeqNum = tagInfo.getSeqNum();
			}
			for (RangeActivation range : activityTagRange) {
				if (rangeSeqNum >= range.getSeqnumStart() && rangeSeqNum <= range.getSeqnumEnd()) {// 该码已经被激活
					tagInfo.setStatus(TagRangeStatus.ACTIVATED.getValue());
					tagInfo.setStatusName(TagRangeStatus.ACTIVATED.getName());
					tagInfo.setUpdateUserId(range.getUpdateUserId());
					tagInfo.setFactoryId(range.getFactoryId());
					tagInfo.setProductId(range.getProductId());
					tagInfo.setFranchiserId(range.getFranchiserId());
				}

			}
		}
		return tagInfo;
	}

	/**
	 * 设置加密串,友好码
	 * 
	 * @param tagInfo
	 * @throws Exception
	 */
	private TagStatusInfoDto setMixAndCodes(TagStatusInfoDto tagInfo, TagBatch tagBatch, Integer tagCountPerLine,
			Integer direction) throws Exception {

		Path localBackPath = getTagBackFilePath(tagInfo);// 获取备份文件路径
		if (localBackPath == null) {
			return new TagStatusInfoDto(CommonCode.FILE_NOT_EXIST.getId(), "not found tag batch print file!");
		}
		RandomAccessFile accessFile = new RandomAccessFile(localBackPath.toFile(), "r");
		Integer lineNum = tagBatch.getTagCount().intValue() / tagCountPerLine;// 总行数
		long lineLen = accessFile.length() / lineNum;// 每行长度
		long seqLineNum = 0;// 行下标指针

		Integer tagBatchType = tagInfo.getBatchType();// 批次类型

		if (tagBatchType == TAG_BATCH_TYPE.NORMAL.getValue() || tagBatchType == TAG_BATCH_TYPE.ROLL.getValue()) {// 标准码,卷标排序
			if (direction == PrintFileSortDirection.Transverse.getValue()) {// 横向排列
				seqLineNum = (tagInfo.getSeqNum() - tagBatch.getSeqnumStart()) / tagCountPerLine;
			} else if (direction == PrintFileSortDirection.Vertical.getValue()) {// 纵向排列
				for (int i = 0; i < tagCountPerLine; i++) {
					if (tagInfo.getSeqNum() <= tagBatch.getSeqnumStart() + lineNum * (i + 1) - 1) {
						seqLineNum = tagInfo.getSeqNum() - tagBatch.getSeqnumStart() + lineNum * i;
						break;
					}
				}
			} else {

			}
		} else if (tagBatchType == TAG_BATCH_TYPE.PACKAGE.getValue()) {// 套标
			if (tagInfo.getSeqNum() <= tagBatch.getSeqnumStart() + lineNum - 1) {// 不大于最后一个父标
				seqLineNum = tagInfo.getSeqNum() - tagBatch.getSeqnumStart();
			} else {
				seqLineNum = (tagInfo.getSeqNum() - (tagBatch.getSeqnumStart() + lineNum)) / (tagCountPerLine - 1);
			}
		} else {// 双标(每行一个)
			seqLineNum = tagInfo.getSeqNum() - tagBatch.getSeqnumStart();
		}

		accessFile.seek(seqLineNum * lineLen);// 跳到某个位置(指针位置)
		String[] tagsLine = accessFile.readLine().split(";");
		for (int j = 0; j < tagsLine.length; j++) {
			TagCode tagCode = jsonMapper.fromJson(tagsLine[j], TagCode.class);
			if (tagCode.getSeqNum() == tagInfo.getSeqNum()) {
				tagInfo.setFriendlyCode(tagCode.getMixed());
				List<String> codes = new ArrayList<>();
				while (tagCode != null) {
					codes.add(tagCode.getCode());
					if (tagCode.getTwin() != null) {
						tagCode = tagCode.getTwin();
					} else {
						break;
					}
				}
				tagInfo.setCodes(codes);
				break;
			}
		}
		accessFile.close();
		return tagInfo;
	}

	private synchronized Path getTagBackFilePath(TagStatusInfoDto tagInfo) throws Exception {
		// 本地临时存储云文件相对路径
		Path tempPath = Paths.get(tempBackFilePath);
		if (!Files.exists(tempPath)) {
			Files.createDirectories(tempPath);
		}
		String tagBackPath = tempBackFilePath + tagInfo.getBatchId();// 本地备份路径

		Path localBackPath = Paths.get(tagBackPath + ".txt");// 指向解压后的txt文件
		if (!Files.exists(localBackPath)) {// 本地环境没有,则去云端下载
			String tempZipBackPath = tagBackPath + ".zip";// 临时zip备份文件路径
			// 云端备份路径
			String uploadBackPath = tagCodeBackupPath + tagInfo.getBatchId() + ".zip";

			localBackPath = fileService.downloadAsFile(codeInitFiles, uploadBackPath, tempZipBackPath, true);
			if (!Files.exists(localBackPath)) {// 备份文件获取有误

				return null;
			} else {
				CipherZipUtil.unzip(tempZipBackPath, null);// 得到解压后的txt文件
				Files.delete(localBackPath);// 删除zip源文件

				localBackPath = Paths.get(tagBackPath + ".txt");// 指向解压后的txt文件
			}
		}
		return localBackPath;
	}

	/**
	 * 获取标签序号
	 * 
	 * @param query
	 * @return
	 * @throws Exception
	 */
	@Override
	public long getTagSeqNum(String query) throws Exception {
		query = StringUtils.trim(query);
		long seqNum = 0l;
		if (StringUtils.isNotEmpty(query)) {
			try {
				seqNum = Long.parseLong(query);
			} catch (NumberFormatException e) {

				if (query.startsWith("HTTP://") || query.startsWith("HTTPS://")) {// 二维码url
					String[] tagUrl = query.split("/");// 码url
					int len = tagUrl.length;
					if (len >= 3) {
						String encryptCode = tagUrl[len - 1].split("\\?")[0];// 加密串(可能包含?a=23432432)
						String subDomain = tagUrl[len - 2];// 子域名
						// String domain = tagUrl[len - 3];// 域名
						TagCode tagCode = tagDecryptor.decode(subDomain, encryptCode);
						if (tagCode != null) {
							seqNum = tagCode.getSeqNum();
						}
					}
				} else {// friendcode
					seqNum = TagCodeDriver.decodeMixed(query);
				}
			}
		}
		return seqNum;
	}

	@Override
	public TagStatusInfoDto getTagBaseInfoBy(String tagParam) {
		try {
			return getTagStatusInfoBy(tagParam, false);
		} catch (Exception e) {
			return new TagStatusInfoDto(CodeMessage.InvalidRequest.getId(), tagParam + "/" + e.getMessage());
		}
	}
}
